package com.ayh.campusfun.common.core.oss;

import cn.hutool.core.util.RandomUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.ObjectMetadata;
import com.ayh.campusfun.common.OSSResult;
import com.ayh.campusfun.common.core.config.OSSConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
import ws.schild.jave.MultimediaInfo;
import ws.schild.jave.MultimediaObject;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.*;

/**
 * @author ayh
 * @create 2021/4/2 0002 14:22
 * OSSService实现类
 */

@Service
@Slf4j
public class OSSServiceImpl implements OSSService {
    @Autowired
    private OSSConfiguration ossConfig;

    @Autowired
    OSS ossClient;


    @Override
    public OSSResult uploadFile(MultipartFile file, String storagePath) {
        String fileName = "";
        String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        try {
            fileName = UUID.randomUUID().toString();
            InputStream inputStream = file.getInputStream();
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(file.getContentType());
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            fileName = storagePath + "/" + fileName + suffixName;
            // 上传文件
            ossClient.putObject(ossConfig.getBucketName(), fileName, inputStream, objectMetadata);
        } catch (IOException e) {
            log.error("Error occurred: {}", e.getMessage(), e);
        }
        return OSSResult.builder()
                .nativeName(file.getName())
                .fileName(fileName)
                .fileType(file.getContentType())
                .fileUrl(ossConfig.getUrl() + fileName)
                .build();
    }


    /**
     * 获取视频缩略图
     *
     * @param filePath：视频路径
     * @throws Exception
     */
    @Override
    public OSSResult randomGrabberFFmpegVideoImage(String filePath) throws Exception {
        OSSResult targetFilePath = null;
        FFmpegFrameGrabber ff = FFmpegFrameGrabber.createDefault(filePath);
        ff.start();
        //判断是否是竖屏小视频
        String rotate = ff.getVideoMetadata("rotate");
        int ffLength = ff.getLengthInFrames();
        Frame f;
        int i = 0;
        int index = ffLength / 2;//截取图片第几帧
        while (i < ffLength) {
            f = ff.grabImage();
            if (i == index) {
                if (null != rotate && rotate.length() > 1) {
                    targetFilePath = doExecuteFrame(f, true);   //获取缩略图
                } else {
                    targetFilePath = doExecuteFrame(f, false);   //获取缩略图
                }
                break;
            }
            i++;
        }
        ff.stop();
        return targetFilePath;  //返回的是视频第N帧
    }

    @Override
    public List<OSSResult> uploadFiles(MultiValueMap<String, MultipartFile> files, String storagePath) {
        List<OSSResult> list = new ArrayList<>();
        Set<Map.Entry<String, MultipartFile>> multipartSet = files.toSingleValueMap().entrySet();
        for (Map.Entry<String, MultipartFile> stringMultipartFileEntry : multipartSet) {
            OSSResult ossResult = uploadFile(stringMultipartFileEntry.getValue(), storagePath);
            list.add(ossResult);
        }
//        for(String key: files.keySet()){
//            OSSResult ossResult = uploadFile((MultipartFile) files.get(key), storagePath);
//            list.add(ossResult);
//        }
        return list;
    }

    @Override
    public Long getTime(MultipartFile file) {
        File tempFile = null;
        long duration = 0L;
        try {
            tempFile = File.createTempFile(RandomUtil.randomString(10), "." + FilenameUtils.getExtension(file.getOriginalFilename()));
            file.transferTo(tempFile);
            MultimediaObject multimediaObject = new MultimediaObject(tempFile);
            MultimediaInfo info = multimediaObject.getInfo();
            duration = info.getDuration();
        } catch (Exception e) {
            log.error("获取视频时长失败", e);
        } finally {
            if (tempFile != null) {
                tempFile.delete();
            }
        }
        return duration;
    }

    /**
     * 截取缩略图，存入阿里云OSS（按自己的上传类型自定义转换文件格式）
     *
     * @param f
     * @return
     * @throws Exception
     */
    public OSSResult doExecuteFrame(Frame f, boolean bool) throws Exception {
        if (null == f || null == f.image) {
            return null;
        }
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage bi = converter.getBufferedImage(f);
        if (bool == true) {
            Image image = (Image) bi;
            bi = rotate(image, 90);//图片旋转90度
        }
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(bi, "png", os);
        byte[] sdf = os.toByteArray();
        InputStream input = new ByteArrayInputStream(os.toByteArray());
        MultipartFile multipartFile = new MockMultipartFile("temp.jpg", "temp.jpg", "image/jpeg", input);
        OSSResult ossResult = uploadFile(multipartFile, "JIETU");
        return ossResult;
    }

    /**
     * 图片旋转角度
     *
     * @param src   源图片
     * @param angel 角度
     * @return 目标图片
     */
    public static BufferedImage rotate(Image src, int angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // calculate the new image size
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);

        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = res.createGraphics();
        // transform(这里先平移、再旋转比较方便处理；绘图时会采用这些变化，绘图默认从画布的左上顶点开始绘画，源图片的左上顶点与画布左上顶点对齐，然后开始绘画，修改坐标原点后，绘画对应的画布起始点改变，起到平移的效果；然后旋转图片即可)

        //平移（原理修改坐标系原点，绘图起点变了，起到了平移的效果，如果作用于旋转，则为旋转中心点）
        g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2);


        //旋转（原理transalte(dx,dy)->rotate(radians)->transalte(-dx,-dy);修改坐标系原点后，旋转90度，然后再还原坐标系原点为(0,0),但是整个坐标系已经旋转了相应的度数 ）
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

//        //先旋转（以目标区域中心点为旋转中心点，源图片左上顶点对准目标区域中心点，然后旋转）
//        g2.translate(rect_des.width/2,rect_des.height/ 2);
//        g2.rotate(Math.toRadians(angel));
//        //再平移（原点恢复到源图的左上顶点处（现在的右上顶点处），否则只能画出1/4）
//        g2.translate(-src_width/2,-src_height/2);


        g2.drawImage(src, null, null);
        return res;
    }

    /**
     * 计算转换后目标矩形的宽高
     *
     * @param src   源矩形
     * @param angel 角度
     * @return 目标矩形
     */
    private static Rectangle CalcRotatedSize(Rectangle src, int angel) {
        double cos = Math.abs(Math.cos(Math.toRadians(angel)));
        double sin = Math.abs(Math.sin(Math.toRadians(angel)));
        int des_width = (int) (src.width * cos) + (int) (src.height * sin);
        int des_height = (int) (src.height * cos) + (int) (src.width * sin);
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }

}
